home *** CD-ROM | disk | FTP | other *** search
/ Mac100% 1998 November / MAC100-1998-11.ISO.7z / MAC100-1998-11.ISO / オンラインソフト定点観測 / ユーティリティ / Mops 3.2.sea / Mops 3.2 / Mops source / PPC source / cg6 < prev    next >
Text File  |  1998-06-22  |  45KB  |  1,847 lines

  1. PPC?
  2. [IF]
  3. false    constant    debug?
  4. [ELSE]
  5. false    constant    debug?
  6. [THEN]
  7.  
  8.  
  9.  
  10. ¥    ===============  SUNDRY INDIVIDUAL HANDLERS  ==================
  11.  
  12. OD    valOD
  13.  
  14. PPC? not
  15. [IF]
  16.  
  17. : 68kReg>PPC  { reg# ¥ regType -- ppc-reg# }
  18.     reg# $ E0 and  -> regType    ¥ 0 Dn, $20 FPn, $40 An, $60 already a PPC reg
  19.     reg# $ 1F and  -> reg#
  20.  
  21.     regType
  22.     CASE[    $ 60    ]=>            reg#    ¥ already a PPC reg# - leave unchanged
  23.           
  24.         [    0        ]=>                    ¥ Dn on 68k
  25.             reg#
  26.             SELECT[    1    ]=>        0
  27.                     [    3    ]=>        I_reg
  28.                   DEFAULT=>        drop  0
  29.             ]SELECT
  30.             
  31.         [    $ 20    ]=>
  32.         
  33.         [    $ 40    ]=>                    ¥ An on 68k
  34.             reg#
  35.             SELECT[    2    ]=>        obj_base_reg
  36.                   [    3    ]=>        mainData_reg
  37.                   [    4    ]=>        mainData_reg
  38.                   [    5    ]=>        modData_reg
  39.                   DEFAULT=>        db drop  0
  40.             ]SELECT
  41.  
  42.         DEFAULT=>    db
  43.     ]CASE
  44. ;
  45.  
  46. [THEN]
  47.  
  48.  
  49. : ^EXTRA_INFO  { cfa -- addr }
  50.     cfa c@  $ FF =
  51.     IF  2  ELSE  4  THEN  cfa +  ;
  52.  
  53.  
  54. PPC?
  55. [IF]
  56.  
  57. : genAddr  { base-reg displ ind# -- }
  58.  
  59. (*    Rather similar to litaddr_h.  Called via (OBJ) when we are compiling
  60.     an inline method, and generating the object address.  The "base-reg" may
  61.     be negative, in which case the "displ" is an absolute address.
  62.     I suspect ind# will always be zero on the PPC, so I'll trap it if it's
  63.     not.
  64. *)
  65.     ind# if $ deadbeef $ 129 db 2drop then
  66.     
  67.     base-reg 0<
  68.     IF        displ b&d
  69.     ELSE    base-reg  displ
  70.     THEN
  71.     (litAddr)
  72. ;
  73.  
  74. [ELSE]        ¥ only change is to add 68kReg>PPC call.
  75.  
  76. : genAddr  { base-reg displ ind# -- }
  77.  
  78.     ind# if $ deadbeef $ 100 db 2drop then
  79.     base-reg 0<
  80.     IF        displ b&d
  81.     ELSE    base-reg 68kReg>PPC
  82.             displ
  83.     THEN
  84.     (litAddr)
  85. ;
  86.  
  87. [THEN]
  88.  
  89.  
  90. : genXAddr { ixwid ixoffs base-reg displ local-displ ind# flags ¥ lim -- }
  91.  
  92. (*    Called by (IX) when we are compiling an in-line method, and generating
  93.     the address of an indexed element of the current object.
  94.     The base-reg, displ and ind refers to the obj addr.  ixoffs is the offset
  95.     to the indexed area, if we know it.  This will happen if the obj
  96.     is a straight object or an ivar (ivars are generic to a class, but
  97.     each one has a fixed ixoffs).  In these cases we can absorb the ixoffs
  98.     at compile time.  If, however, the "obj" is self or super, then we won't
  99.     know the ixoffs at compile time, since at different points in the class
  100.     hierarchy the ixoffs is different.  It is always located at run time
  101.     2 bytes after the class pointer (this is changed from 68k).  In this
  102.     case we will pass in a negative "ixoffs".
  103.     As for hGenaddr, the "base-reg" may be negative, which means that the
  104.     "displ" is actually an absolute addr.
  105. *)
  106.  
  107.     -1 -> lim
  108.     base-reg 0<
  109.     IF    displ ixoffs + 4- @  -> lim  THEN
  110.  
  111.     ixoffs 0<
  112.     IF    " (^base) 2- dup w@x +"  evaluate
  113.         range_check?
  114.         IF  " 2dup 4- @ u> ?trap"  evaluate  THEN
  115.     ELSE
  116.         base-reg  displ ixoffs + local-displ +  ind#  genAddr
  117.                 ¥ note - we can't just add the local-displ if ind# is nonzero,
  118.                 ¥  but I think on the PPC we can arrange for it to always be
  119.                 ¥  zero (and we'll get rid of it altogether eventually).
  120.  
  121. ¥ run time: ( index ^indexed-area )
  122.  
  123.         range_check?
  124.         IF
  125.             lim 0<
  126.             IF
  127.                 " 2dup 4- @ u> ?trap"
  128.             ELSE            ¥ we have the object available
  129.                 " over" evaluate        ¥ get index
  130.                 lim  postpone literal
  131.                 " u> ?trap"
  132.             THEN
  133.             evaluate
  134.         THEN
  135.     THEN
  136.  
  137.     swap_cstk
  138.  
  139.     debug? if
  140.         ." about to gen indexed addr - cstk:" printall: cstk
  141.     then
  142.     ixwid 1 > IF  ixwid  postpone literal  postpone *  THEN
  143.     postpone +
  144.     debug? if
  145.         ." afterwards - cstk:" printall: cstk
  146.     then
  147. ;
  148.  
  149.  
  150. : hStkObj    ¥ ( -- base-reg displ )
  151.  
  152. (*    Sets up for an early bind to an object whose
  153.     (data) addr is on the stack at run time.  We also handle object
  154.     pointers this way, by first compiling a fetch of the objPtr
  155.     to the stack, and relying on our optimization to improve the code.
  156.     Rather than leaving the ^obj on the stack, we return the addressing
  157.     info back to the CLASS code.  This is because we may be binding to an
  158.     inline method which uses OBJ anywhere - more than once, even.
  159. *)
  160.     debug? if
  161.         ." hStkObj called - cstk:"  printall: cstk cr
  162.     then
  163.     1 operands
  164.     reftype: opnd1 gprRef <>  IF  210 die  THEN        ¥ "can't bind to that"
  165. ¥    opnd1 get_to_reg? drop
  166.     gpr: opnd1
  167. [ ppc? not ]
  168. [if]
  169.     $ 60 or        ¥ the $60 marks this as a PPC reg, when target
  170.                 ¥  compiling only
  171. [then]
  172.     0
  173. ¥ Note: we mustn't  free: opnd1  here, since the upcoming early_bind
  174. ¥  call may execute inline code which allocates a reg!
  175. ;
  176.  
  177.  
  178. : CREATE_H    litAddr_h  ;
  179. : BUILDS_H    4+  litAddr_h  ;
  180. : OBJ_H        litAddr_h  ;        ¥ ptr points to obj's data, 12 bytes after
  181.                                 ¥  the obj header
  182.  
  183.  
  184. ppc? not
  185. [IF]
  186.  
  187. : CLASS_H    db  ;        ¥ mustn't get called on the 68k - ppc_obj is what gets
  188.                         ¥  called.  The proper PPC class_h is defined in qpClass.
  189.  
  190. [THEN]
  191.  
  192.  
  193. : DO_FETCH  { len flags ¥ reg#  -- }
  194.     1 operands
  195.     debug? if
  196.         ." do_fetch - opnd1: " cr print: opnd1
  197.     then
  198.  
  199.     addr: opnd1  get_to_gpr? drop
  200.  
  201.     clear: theOD
  202.     otFetch put: ivar> opType    in theOD
  203.     len        put: ivar> len        in theOD
  204.     flags    put: ivar> flags    in theOD
  205.  
  206.     gpr: opnd1    dup -> reg#    >Agpr: theOD
  207.     0                        >Blit: theOD
  208.  
  209.     cascade&match?
  210.     
  211.     debug? if
  212.         ." matched? " dup if ." yes" else ." no" then cr
  213.     then
  214.     
  215.     NIF    1 results
  216.         theOD copyWithoutCDP: GPRs
  217.         compile: GPRs
  218.         free: opnd1
  219.     THEN
  220.  
  221.     res1 push
  222. ;
  223.  
  224.  
  225. : DO_FP_FETCH  { len ¥ reg# -- }
  226.     1 operands
  227.  
  228.     debug? if
  229.         ." do_FP_fetch - opnd1: " cr print: opnd1
  230.     then
  231.  
  232.     addr: opnd1  get_to_gpr? drop
  233.  
  234.     clear: theOD
  235.     otFPfetch    put: ivar> opType in theOD
  236.     len            put: ivar> len in theOD
  237.  
  238.     gpr: opnd1    dup -> reg#    >Agpr: theOD
  239.     0                        >Blit: theOD
  240.  
  241.     cascade&match?
  242.     
  243.     debug? if
  244.         ." matched? " dup if ." yes" else ." no" then cr
  245.     then
  246.  
  247.     NIF    1 fresults
  248.         theOD copyWithoutCDP: FPRs
  249.         compile: FPRs
  250.         free: opnd1
  251.     THEN
  252.     res1 fpush
  253. ;
  254.  
  255.  
  256. (* RECORD_GPR_STORE puts an entry for the passed-in OD in stored_GPRs,
  257. in case we can optimize out a subsequent fetch of the same location
  258. (i.e. in the case where the stored value is still sitting in the reg
  259. we stored it from).
  260.  
  261. We used to simply change the op in the stored GPR to a fetch, so it
  262. could match any subsequent fetch of that location.  But it's better
  263. to keep a separate record in stored_GPRs, and check there for a match.
  264. This has the same effect, but means we don't have to clobber the prev
  265. info in the reg's OD - we might be able to match on the op that
  266. generated the value.  Even if the GPR's type is otUnknown, although 
  267. we won't be able to match on it, we still might be able to optimize
  268. out a subsequent fetch of the same location we're storing into.  So
  269. we change the type to otUnkStored, which will mean we hang on to it
  270. a bit longer than otUnknown (which are up for grabs as soon as we need
  271. to allocate a free reg).
  272.     
  273. We also clobber any fetch of the target location that might
  274. still be sitting around in a reg, since that value isn't valid any more.
  275.  
  276. Special note: we don't record partial word stores, since in the
  277. general case, a fetch of that location WON'T be equal to the
  278. reg we stored from, and it's not worth trying to sort this out.
  279. *)
  280.  
  281.  
  282. OD    storedOD
  283.  
  284. objPtr whichRegs    class_is ODs_class
  285. objPtr stored_regs    class_is ODs_class
  286.  
  287. : RECORD_REG_STORE  { ^OD ¥ reg# -- }
  288.  
  289.     ^OD  copyOD: storedOD
  290.  
  291.     debug? if
  292.         ." recording store of " print: storedOD
  293.     then
  294.  
  295.     reg: opnd2  -> reg#            ¥ the reg we've stored
  296.     reg# select: whichRegs
  297.     CDP 4-  mark_use: whichRegs
  298.  
  299.     get: ivar> len in storedOD  4 <
  300.     IF    debug? if
  301.             ." no - len < 4 - not recording"
  302.         then
  303.         EXIT
  304.     THEN
  305.  
  306.     reg# select: stored_regs
  307.  
  308.     ^OD  copyOD: stored_regs
  309.  
  310.     get: ivar> opCDP        in whichRegs
  311.     put: ivar> lastRefCDP    in stored_regs
  312.  
  313.     CDP 4-  put: ivar> lastRefCDP in whichRegs
  314.     get: ivar> opType in whichRegs  otUnknown =
  315.     IF  otUnkStored  put: ivar> opType in whichRegs  THEN
  316.  
  317. (*
  318.     storedOD false  match?: whichRegs
  319.     IF    otUnknown  put: ivar> opType in whichRegs
  320.         noType       put: ivar> instrnType in whichRegs
  321.         addr: ivar> myRef in whichRegs  ->: tmpRef1
  322.         4 --> CDP
  323.         tmpRef1 reg_changed
  324.         4 ++> CDP
  325.         CDP 4-  put: ivar> validTillCDP in whichRegs
  326.         debug? if
  327.             ." invalidated earlier fetch of same location:"    print: whichRegs  cr
  328.         then
  329.     THEN
  330. *)
  331.  
  332.     reg# select: whichRegs
  333.     
  334.     debug? if
  335.         ." updated stored_regs:" cr printall: stored_regs cr
  336.     then
  337. ;
  338.  
  339.  
  340. : RECORD_GPR_STORE
  341.     GPRs -> whichRegs  stored_GPRs -> stored_regs
  342.     record_reg_store
  343. ;
  344.  
  345. : RECORD_FPR_STORE
  346.     FPRs -> whichRegs  stored_FPRs -> stored_regs
  347.     record_reg_store
  348. ;
  349.  
  350. (*
  351. : RECORD_FPR_STORE  { ^OD ¥ reg# -- }
  352.     FPR: opnd2  select: stored_FPRs
  353.     theOD copyWithCDP: stored_FPRs
  354.     get: ivar> opCDP        in FPRs
  355.     put: ivar> lastRefCDP    in stored_FPRs
  356. ;
  357. *)
  358.  
  359. : COMPILE_THE_STORE  { ¥ gpr# -- }
  360.     Agpr: theOD  -> gpr#
  361.  
  362.     refType: opnd2
  363.     CASE[    gprRef    ]=>        reg: opnd2 select: GPRs
  364.                             CDP put: ivar> lastRefCDP in GPRs
  365.                             
  366.         [    fprRef    ]=>        reg: opnd2 select: FPRs
  367.                             CDP put: ivar> lastRefCDP in FPRs
  368.  
  369.           DEFAULT=>            drop
  370.     ]CASE
  371.  
  372.     gpr# 13 16 within?
  373.     swap obj_base_reg = or
  374.     refType: ivar> B_opnd in theOD  litRef =  and
  375.  
  376.     NIF    
  377.         debug? if
  378.             ." it's a computed store" cr  print: theOD cr
  379.             ." current GPR " current: gprs . cr
  380.         then
  381.         free: opnd2        ¥ free the data reg - freeing it early is safe,
  382.                         ¥  and lets make_fetches_unknown mark the reg as
  383.                         ¥  "empty" so it can be reallocated
  384.  
  385.         make_fetches_unknown: GPRs
  386.         make_fetches_unknown: FPRs
  387.         invalidate_all: stored_GPRs
  388.         invalidate_all: stored_FPRs
  389.          compile: theOD
  390.         CDP -> backstop_CDP
  391.     ELSE
  392.  
  393.         theOD  invalidate_on_overlap: GPRs
  394.         theOD  invalidate_on_overlap: FPRs
  395.         theOD  invalidate_on_overlap: stored_GPRs
  396.         theOD  invalidate_on_overlap: stored_FPRs
  397.  
  398.         compile: theOD
  399.         free: opnd2        ¥ free the data reg
  400.  
  401. (*    Now we copy theOD to the corresponding stored_GPRs or stored_FPRs
  402.     location, and set the lastRefCDP ivar.  Note that this ivar has a
  403.     special meaning for stores - it's the CDP for where the stored reg's
  404.     value was generated.  The normal meaning wouldn't make sense for
  405.     stores anyway.
  406. *)
  407.         refType: opnd2
  408.         CASE[    gprRef    ]=>        theOD  record_GPR_store
  409.             [    fprRef    ]=>        theOD  record_FPR_store
  410.  
  411.               DEFAULT=>        to_be_written  drop
  412.         ]CASE
  413.  
  414. (*    Finally we set the fetch backstop to straight after the store, so that
  415.     we won't move any fetch forward past this point.  To be able to do this,
  416.     we'd need to do a full check for overlap possibilities, since any overlap
  417.     would invalidate moving the fetch forward.  This is doable, but rather
  418.     complicated, since we may have already invalidated the record of an
  419.     earlier store, so we'd need to keep a bytestring with info about all
  420.     stores in the current definition.  We could do this, but it's nasty, and
  421.     probably not worth it just for this situation, which will probably
  422.     hardly ever slow down a fetch anyway.
  423. *)
  424.         CDP -> fetch_backstop
  425.     THEN
  426. ;
  427.  
  428.  
  429. : DO_OP&STORE { len ¥ theOp -- }
  430.  
  431. (*    This handles an op into memory, such as ++> aValue.  We fetch, operate,
  432.     store.  On entry, the top of cstk is a reference to a reg with the target
  433.     addr.  The second cell is a ref to the reg we're operating into that target.
  434.     We start off with do_fetch which may cascade the address add.  Whatever it
  435.     does, it should leave the dest reg selected (where the data was fetched to).
  436.     This will designate the actual fetch operation done, and we can use
  437.     exactly this reg info to do the store later.  We ensure that any antecedent
  438.     regs aren't changed between the fetch and the store by bumping their refcnts
  439.     for the duration.
  440. *)
  441.     debug? if
  442.         ." do_op&store called" cr
  443.     then
  444.  
  445.     svOpcode -> theOp            ¥ gets clobbered
  446.     len 0 do_fetch                ¥ do the fetch - dest GPR left selected
  447.     gpr: cstk select: GPRs        ¥ but in case it wasn't, we ensure it is.
  448.                                 ¥ &&&& FPRs to_be_written !!!
  449.  
  450.     debug? if
  451.         ." fetch done, to GPR: " cr  print: GPRs
  452.     then
  453.  
  454.     addr: GPRs   copyOD: tmpOD            ¥ save target OD, since we'll store
  455.                                         ¥  using it shortly
  456.     allocate: ivar> A_opnd in tmpOD        ¥ Ensure any base regs needed for the
  457.     allocate: ivar> B_opnd in tmpOD        ¥  store, aren't clobbered by the op
  458.     otStore  put: ivar> opType in tmpOD
  459.     
  460. ¥ at this point the cstk is ( stk-opnd mem-opnd ). We now need
  461. ¥  to (in effect) postpone a SWAP, since if the op is subtract,
  462. ¥  the stk-opnd must be subtracted from the mem-opnd.
  463.  
  464.     swap_cstk
  465.     theOp -> operation  do_arith_op        ¥ do the operation
  466.     
  467.     1 operands                    ¥ get the result reg (will normally be different)
  468.     opnd1 ->: opnd2                ¥ compile_the_store expects it in opnd2
  469.     opnd1 ->: ivar> myRef in tmpOD
  470.                                 ¥ but the store of that reg will be to the location
  471.                                 ¥  we got before
  472.     debug? if
  473.         ." result reg:" gpr: opnd1  .g  cr
  474.     then
  475.  
  476.     tmpOD copyOD: theOD
  477.     
  478.     debug? if
  479.         ." theOD before store:" print: theOD cr
  480.     then
  481.     
  482.     compile_the_store
  483.         
  484.     debug? if  dasm  then
  485.  
  486.     free: ivar> A_opnd in tmpOD        ¥ Because we did allocate: on them above
  487.     free: ivar> B_opnd in tmpOD
  488. ;
  489.  
  490.  
  491. : (DO_STORE)        ¥ factors out common code from DO_STORE and DO_FP_STORE.
  492.  
  493.     opnd2 >myRef: theOD        ¥ the reg we're storing
  494.  
  495.     gpr: opnd1      >Agpr: theOD
  496.     0 >Blit: theOD
  497.     
  498.     debug? if
  499.         ." (do_store) called, with a straight store" cr
  500.         ." - initial store set up in theOD:" cr print: theOD cr
  501.         dasm
  502.     then
  503.  
  504.     cascade&match? drop        ¥ stores never match anything, but a cascade
  505.                             ¥  might get done
  506.     debug? if
  507.         ." after cascade&match?" cr print: theOD cr
  508.         ." opnd2 " print: opnd2 cr
  509.     then
  510.  
  511. ¥    opnd2 >myRef: theOD        ¥ the reg we're storing
  512.     debug? if
  513.         ." theOD set up for store:" cr print: theOD cr
  514.     then
  515.     compile_the_store
  516.  
  517.     free: opnd1            ¥ free the dest addr reg - if we cascaded, this will
  518.                         ¥  have been deleted, but then opnd1 will have been
  519.                         ¥  changed to noRef and the free: will be ignored.
  520. ;
  521.  
  522.  
  523. : DO_STORE  { len ¥ regForStore -- }
  524.  
  525.     debug? if
  526.         ." do_store called with opcode " svOpcode .h cr
  527.         printall: cstk  dasm
  528.     then
  529.  
  530.     svOpcode dup otStore <>  swap otFPstore <>  and
  531.     IF    len do_op&store  EXIT  THEN
  532.  
  533. ¥ cascade&match? wants the address operand in opnd1, so we'll get
  534. ¥  them in reverse order:
  535.  
  536.     swap_cstk  2 operands    ¥ opnd2 = what we're storing, opnd1 = where
  537.     
  538.     refType: opnd2
  539.     SELECT[    gprRef    ]=>                ¥ nothing to do
  540.           [    litRef    ]=>        opnd2 get_to_reg? drop
  541.           
  542.           [    crRef    ]=>        opnd2  0  cr>this_gpr
  543.                               0 >gpr: opnd2
  544.  
  545.           DEFAULT=>            drop
  546.     ]SELECT
  547.  
  548. ¥ Now we have to check that the destination makes sense:
  549.  
  550.     refType: opnd1
  551.  
  552.     SELECT[    gprRef    ]=>                    ¥ nothing to do
  553.           [    litRef    ]=>        opnd1 get_to_gpr? drop
  554.  
  555.           DEFAULT=>            214 die        ¥ impossible store destination!
  556.     ]SELECT
  557.  
  558. ¥ now we set things up in theOD, since we might be able to cascade the addr.
  559.  
  560.     clear: theOD
  561.     otStore        put: ivar> opType    in theOD
  562.     len            put: ivar> len        in theOD
  563.     
  564.     (do_store)
  565. ;
  566.  
  567.  
  568. : DO_FP_STORE  { len -- }
  569.  
  570.     debug? if
  571.         ." do_FP_store called with opcode " svOpcode .h cr
  572.         printall: cstk
  573.     then
  574.     
  575. ¥ cascade&match? wants the address operand in opnd1, so we'll
  576. ¥  organize things that way:
  577.  
  578.     1 foperands  opnd1 ->: opnd2        ¥ opnd2 = what we're storing
  579.     1 operands                            ¥ opnd1 = where
  580.     
  581.     ASSERT{ refType: opnd2  FPRref = }
  582.  
  583. ¥ now we set things up in theOD, since we might be able to cascade the addr.
  584.  
  585.     clear: theOD
  586.     otFPStore    put: ivar> opType    in theOD
  587.     len            put: ivar> len        in theOD
  588.     
  589.     (do_store)
  590. ;
  591.  
  592.  
  593.  
  594. : SIZE>LEN                    ¥ converts our size codes to a length in bytes
  595.     SELECT[    0    ]=>        1
  596.           [    1    ]=>        2
  597.           [    2    ]=>        4
  598.           [    3    ]=>        8
  599.     DEFAULT=>
  600.     ]SELECT
  601. ;
  602.  
  603.  
  604. : @_H  { cfa ¥ flags size -- }
  605.     cfa ^extra_info -> cfa
  606.     cfa 1+ c@ -> size
  607.     cfa 3+ c@ -> flags
  608.     size size>len flags  do_fetch  ;
  609.  
  610.  
  611. : !_H  { cfa ¥ flags size -- }
  612.     cfa ^extra_info -> cfa
  613.     cfa    c@ -> svOpcode
  614.     cfa 1+ c@ -> size
  615.     size size>len  do_store  ;
  616.  
  617.  
  618. : F@_H  { cfa -- }    8  do_fp_fetch  ;
  619. : SF@_H  { cfa -- }    4  do_fp_fetch  ;
  620.  
  621. : F!_H  { cfa -- }  8  do_fp_store  ;
  622. : SF!_H { cfa -- }  4  do_fp_store  ;
  623.  
  624.  
  625.  
  626.  
  627. PPC? not
  628. [IF]
  629.  
  630. (*    Here in 68k mode we define some interim versions of some of our
  631.     floating point operations.  This allows us do some testing on the
  632.     FP code generation without having to load everything, and also lets
  633.     us target compile code in Setup to initialize the FP regs.
  634.     
  635.     As interim ops, these are immediate and can only be used in a
  636.     definition.
  637. *)
  638.  
  639. : F@    8  do_fp_fetch  ;    immediate
  640. : F!    8  do_fp_store  ;    immediate
  641.  
  642. : SF@    4  do_fp_fetch  ;    immediate
  643. : SF!    4  do_fp_store  ;    immediate
  644.  
  645. : F+    otFADD -> operation  dyadic_arith  ;        immediate
  646. : F-    otFSub -> operation  dyadic_arith  ;        immediate
  647. : F*    otFMUL -> operation  dyadic_arith  ;        immediate
  648. : FDROP    tmpRef1 fpop  free: tmpRef1  ;                immediate
  649. : FDUP    1 foperands  opnd1 fpush  opnd1 fpush
  650.         allocate: opnd1  ;                            immediate
  651.                             
  652. : FOVER    2 foperands  opnd1 fpush  opnd2 fpush  opnd1 fpush
  653.         allocate: opnd1  ;                            immediate
  654.  
  655. [THEN]
  656.  
  657.  
  658. PPC?
  659. [IF]
  660. ¥ LITERAL is moved back to cg5 - we still need the old defn, and can't
  661. ¥  resort to ppc_immediate since in compiling numbers we need the new defn.
  662.  
  663. [ELSE]
  664.  
  665. : LITERAL    ¥ ( n -- )    Compiles a fetch of n as a literal.
  666.     ¥ We just push onto cstk, hoping we can combine with an
  667.     ¥  op at run time
  668.         clear: opnd1  >lit: opnd1
  669.         opnd1 push  ;                immediate
  670.  
  671. [THEN]
  672.  
  673. : fetchVal
  674.     64bit? IF 8 ELSE 4 THEN
  675.     0
  676.     do_fetch  ;
  677.     
  678.  
  679. : storeVal
  680.     64bit? IF 8 ELSE 4 THEN
  681.     do_store
  682. ;
  683.  
  684.  
  685. : VAL_H  { ^value -- }
  686.  
  687.     debug? if
  688.         ." val_h" cr
  689.     then
  690.  
  691.     ^value  2+ -> ^value    ¥ align on the reloc addr
  692.  
  693.     ^value @b&d                ¥ get final base reg# and displacement
  694.     (litAddr)                ¥ generates the addr in GPR given by res1 & pushes
  695.  
  696. ¥    gpr: res1  select: GPRs
  697. ¥    GPRs copyOD: valOD        ¥ save the OD in valOD as we may need it
  698.     svOpcode
  699.     NIF                        ¥ it's a fetch
  700.         fetchVal
  701.     ELSE                    ¥ it's some kind of store
  702.         storeVal
  703.     THEN
  704. ;
  705.  
  706. : FVAL_H  { ^value -- }
  707.     debug? if
  708.         ." fval_h" cr
  709.     then
  710.  
  711.     ^value  2+ -> ^value    ¥ align on the reloc addr
  712.  
  713.     ^value @b&d                ¥ get final base reg# and displacement
  714.     (litAddr)                ¥ generates the addr in GPR given by res1 & pushes
  715.  
  716.     svOpcode
  717.     NIF                        ¥ it's a fetch
  718.         8 do_fp_fetch
  719.     ELSE                    ¥ it's some kind of store
  720.         8 do_fp_store
  721.     THEN
  722. ;
  723.  
  724.  
  725. : CONST_H    ¥ ( cfa -- )
  726.     2+
  727.     @  postpone literal  ;        ¥ not too hard!
  728.  
  729. : FCON_H    ¥ ( cfa -- }
  730.     2+ #align8
  731.     lit_addr  postpone f@
  732. ;
  733.  
  734.  
  735. : FETCHREG    ¥ ( reg# code -- )
  736.     3 = IF
  737.         >gpr: opnd1     opnd1 push
  738.     ELSE
  739.         >fpr: opnd1  opnd1 fpush
  740.     THEN
  741.     allocate: opnd1  ;
  742.  
  743.  
  744. : do_reg  { reg# code -- }
  745.     svOpcode
  746.     NIF                    ¥ this is a fetch
  747.         reg# code fetchReg
  748.     ELSE                ¥ this is some kind of store
  749.         svOpcode otStore =
  750.         NIF    reg# code fetchReg
  751.             svOpcode monadic?  NIF swap_cstk THEN
  752.             -> operation  do_arith_op
  753.         THEN
  754.         code 3 =
  755.         IF
  756.             1 operands
  757.             opnd1 get_to_gpr? drop
  758.             gpr: opnd1  reg#  true  moveReg: GPRs
  759.         ELSE
  760.             1 foperands
  761.             fpr: opnd1  reg#  true  moveReg: FPRs
  762.         THEN
  763.     THEN
  764. ;
  765.  
  766.  
  767. ¥ REG_H handles a reg reference - either GPR or FPR.  It's never
  768. ¥  called for a 68k register.
  769.  
  770. : REG_H  { cfa ¥ mode reg# -- }
  771.     cfa ^extra_info -> cfa
  772.     cfa 1+ c@        ¥ reg#
  773.     cfa c@            ¥ code - 3 = gpr, 4 = fpr
  774.     do_reg
  775. ;
  776.  
  777.  
  778. : LOC_H        ¥ note: loc# counts from right to left in the local/parm list,
  779.             ¥ but we're assigning regs from left to right in the list,
  780.             ¥ going from r31 down (since this simplifies EXECUTE).
  781.     drop
  782.     32  #PL loc# -  -  3  do_reg  ;
  783.  
  784. : FLOC_H    ¥ does the same job for floating parms/locals.
  785.     drop
  786.     32  #FPL loc# -  -  4  do_reg  ;
  787.  
  788.  
  789. : VECT_H  { ^vect -- }
  790.  
  791.     ^vect 2+ -> ^vect        ¥ align on the reloc addr
  792.  
  793.     ^vect @b&d                ¥ get final base reg# and displacement
  794.     (litAddr)                ¥ generates the addr in GPR given by res1 & pushes
  795.  
  796.     svOpcode
  797.     NIF                            ¥ it's an execute
  798.         " doVect"  evaluate        ¥ late-bind using evaluate - doVect not defined yet
  799.         true -> ctr_clobbered?    ¥ the vect might do anything!
  800.  
  801.     ELSE                        ¥ it's a store to the vect
  802.         " reloc!"  evaluate
  803.     THEN
  804. ;
  805.  
  806.  
  807. : SVECT_H  { ^vect -- }        ¥ system vectors are like vectors, but have a default
  808.                             ¥ value 4 bytes after the regular one, which gets used
  809.                             ¥ if the regular one is zero.
  810.  
  811.     ^vect 2+ -> ^vect        ¥ align on the reloc addr pointing to data area
  812.  
  813.     ^vect @b&d                ¥ get final base reg# and displacement
  814.     (litAddr)                ¥ generates the addr in GPR given by res1 & pushes
  815.  
  816.     svOpcode
  817.     NIF                            ¥ it's an execute
  818.         " doSvect" evaluate        ¥ late-bind using evaluate - doSvec not defined yet
  819.                                 ¥  the first time through
  820.         true -> ctr_clobbered?    ¥ the vect might do anything!
  821.     ELSE                        ¥ it's a store to the vect
  822.         " reloc!"  evaluate
  823.     THEN
  824. ;
  825.  
  826. (*    Dynamic vectors are "lightweight" vectors in which we don't use a relocatable
  827.     addr but just store the xt to be executed, which allows us to point into
  828.     a module if we know it's safe.  These should never be saved in the dic and used
  829.     after reloading - hence the name "dynamic".  Like system vectors, zero means
  830.     use the default, but the default is always do nothing.
  831. *)
  832.  
  833. : dynVect_h  { ^vect -- }
  834.  
  835.     ^vect 2+ -> ^vect        ¥ align on the reloc addr pointing to data area
  836.  
  837.     ^vect @b&d                ¥ get final base reg# and displacement
  838.     (litAddr)                ¥ generates the addr in GPR given by res1 & pushes
  839.  
  840.     svOpcode
  841.     NIF                            ¥ it's an execute
  842.         " @ execute" evaluate
  843.     ELSE                        ¥ it's a store to the vect
  844.         4 do_store                ¥ store passed-in xt
  845.     THEN
  846. ;
  847.  
  848.  
  849.  
  850. : PM_H      ¥ ( cfa -- )
  851.     ^extra_info
  852.     w@  -> operation  do_arith_op
  853. ;
  854.  
  855.  
  856. : SHIFT_H    ¥ ( cfa -- )
  857.     ^extra_info
  858.     1+ c@  -> subOperation        ¥ 0 left, 1 logical right, 3 arith right
  859.     otShift -> operation  dyadic_arith  ;
  860.  
  861.  
  862. : MULTDIV_H        pm_h  ;
  863.  
  864. : CMP_H  { cfa ¥ 68kCode compWithZero? unsigned? -- }
  865.     cfa ^extra_info -> cfa
  866.     cfa 1+ c@  -> 68kCode
  867.     68kCode $ 10 and -> compWithZero?
  868.     68kCode $ F  and  comparison_codes + c@  -> subOperation
  869.     subOperation 2 and  -> unsigned?
  870.     compWithZero?
  871.     IF        4 or> subOperation  unsigned? monadic_comparison
  872.     ELSE    unsigned? dyadic_comparison
  873.     THEN  ;
  874.  
  875.  
  876. : FPCMP_H  { cfa ¥ code compWithZero? -- }
  877.     cfa ^extra_info  -> cfa
  878.     cfa 1+ c@  -> code
  879.     code $ 4 and -> compWithZero?
  880.     code         -> subOperation
  881.     compWithZero?
  882.     IF        FP_monadic_comparison
  883.     ELSE    FP_dyadic_comparison
  884.     THEN  ;
  885.  
  886.  
  887. : pushDesc_h  { cfa ¥ hndlr -- }
  888.     cfa ^extra_info -> cfa
  889.     cfa c@            ¥ note the code is in the hi byte in case we ever need
  890.                     ¥  a subtype in the lo byte.
  891.  
  892.     CASE[    otDUP    ]=>        ¥ If we're DUPing a CR ref, we're surely not going
  893.                             ¥  to branch on it, but use it as an operand.  We get
  894.                             ¥  much better code if we get it to a GPR straight
  895.                             ¥  away.
  896.                             postpone __>g
  897.                             1 operands
  898.                             opnd1 push  opnd1 push
  899.                             allocate: opnd1
  900.                             
  901.         [    ot2DUP    ]=>        2 operands
  902.                             opnd1 push opnd2 push
  903.                             opnd1 push opnd2 push
  904.                             allocate: opnd1  allocate: opnd2
  905.  
  906.         [    otDROP    ]=>        tmpRef1 pop  free: tmpRef1
  907.         
  908.         [    ot2DROP    ]=>        tmpRef1 pop  free: tmpRef1
  909.                             tmpRef1 pop  free: tmpRef1
  910.  
  911.         [    otSWAP    ]=>        swap_cstk
  912.                             
  913.         [    otOVER    ]=>        2 operands
  914.                             opnd1 push  opnd2 push  opnd1 push
  915.                             allocate: opnd1
  916.                             
  917.         [    $ 68    ]=>        2 operands                                    ¥ NIP
  918.                             free: opnd1
  919.                             opnd2 push
  920.  
  921.         [    $ 69    ]=>        2 operands                                    ¥ TUCK
  922.                             opnd2 push  opnd1 push  opnd2 push
  923.         
  924.         [    $ 6A    ]=>        rot_cstk                                    ¥ ROT
  925.  
  926.         [    $ 6B    ]=>        3 operands                                    ¥ DOWN
  927.                             opnd3 push  opnd1 push  opnd2 push
  928.                             
  929.         [    $ 6C    ]=>        4 operands                                    ¥ 2SWAP
  930.                             opnd3 push  opnd4 push  opnd1 push  opnd2 push
  931.  
  932.         [    $ 6D    ]=>        3 operands                                    ¥ 2PICK
  933.                             opnd1 push  opnd2 push  opnd3 push  opnd1 push
  934.                             allocate: opnd1
  935.  
  936.         [    $ 6E    ]=>        4 operands                                    ¥ 3PICK
  937.                             opnd1 push  opnd2 push  opnd3 push  opnd4 push  opnd1 push
  938.                             allocate: opnd1
  939.  
  940.         [    $ 6F    ]=>        4 operands                                    ¥ 3ROLL
  941.                             opnd2 push  opnd3 push  opnd4 push  opnd1 push
  942.  
  943.         [    $ 72    ]=>        1 foperands                                    ¥ FDUP
  944.                             opnd1 fpush  opnd1 fpush
  945.                             allocate: opnd1
  946.                             
  947.         [    $ 73    ]=>        2 foperands                                    ¥ F2DUP
  948.                             opnd1 fpush opnd2 fpush
  949.                             opnd1 fpush opnd2 fpush
  950.                             allocate: opnd1  allocate: opnd2
  951.  
  952.         [    $ 74    ]=>        tmpRef1 fpop  free: tmpRef1                    ¥ FDROP
  953.         
  954.         [    $ 75    ]=>        tmpRef1 fpop  free: tmpRef1                    ¥ F2DROP
  955.                             tmpRef1 fpop  free: tmpRef1
  956.  
  957.         [    $ 76    ]=>        2 foperands
  958.                             opnd2 fpush  opnd1 fpush                    ¥ FSWAP
  959.  
  960.         [    $ 77    ]=>        2 foperands                                    ¥ FOVER
  961.                             opnd1 fpush  opnd2 fpush  opnd1 fpush
  962.                             allocate: opnd1
  963.                             
  964.         [    $ 78    ]=>        2 foperands                                    ¥ FNIP
  965.                             free: opnd1
  966.                             opnd2 fpush
  967.  
  968.         [    $ 79    ]=>        2 foperands                                    ¥ FTUCK
  969.                             opnd2 fpush  opnd1 fpush  opnd2 fpush
  970.         
  971.         [    $ 7A    ]=>        3 foperands
  972.                             opnd2 fpush  opnd3 fpush  opnd1 fpush         ¥ FROT
  973.  
  974.         [    $ 7B    ]=>        3 foperands                                    ¥ FDOWN
  975.                             opnd3 fpush  opnd1 fpush  opnd2 fpush
  976.  
  977.         [    $ 7C    ]=>        4 foperands                                    ¥ F2SWAP
  978.                             opnd3 fpush  opnd4 fpush  opnd1 fpush  opnd2 fpush
  979.  
  980.  
  981.     DEFAULT=>  drop
  982.     ]CASE
  983. ;
  984.  
  985.  
  986. : SWAP_H    ¥ this is obsolete, but useful in testing before we've loaded
  987.             ¥  the nuc.
  988.     drop  swap_cstk  ;
  989.  
  990.  
  991. : CompJSRlong    compile_call  ;
  992.  
  993.  
  994. : INLINE_H  { cfa -- }
  995.     true -> compinline?
  996.     cfa 1+ count evaluate
  997.     false -> compinline?  ;
  998.  
  999.  
  1000. : INLINE{  { ¥ str-addr --  }
  1001.     drop                            ¥ drop stack flag (ppc_entry will replace)
  1002.     DP                                ¥ Save DP
  1003.     curr-def 2- -> DP                ¥ back to flag bytes (will be replaced after
  1004.                                     ¥  the inline text)
  1005.     method?
  1006.     IF  $ BD40  ELSE  $ BD3C  THEN    ¥ replace handler code with appropriate
  1007.     DP 2- w!                        ¥  inline handler
  1008.     $ FF c,                            ¥ extra info mark, then the string (length in lo
  1009.     DP -> str-addr                    ¥  byte of extra info mark halfword).  Note this
  1010.     & }  ,str                        ¥  does "even" alignment at the end, but since
  1011.                                     ¥  it's starting from an odd byte, DP will be odd.
  1012.                                     ¥  We need to allow for the pad byte that might
  1013.                                     ¥  have been added, and allow for the 2 flag bytes.
  1014.                                     ¥ Thus, if the string length is even, the total
  1015.                                     ¥  len will be odd and there'll be a pad byte.  In
  1016.                                     ¥  this case we add 1 to DP, otherwise 2.
  1017.     str-addr c@ 1 and 1+ ++> DP
  1018.     align                            ¥ Then 4-byte align
  1019.     DP -> CDP
  1020.     -> DP                            ¥ restore DP
  1021.     0 -> state                        ¥ ppc_entry requires compilation off
  1022.     false ppc_entry                    ¥ recompile entry sequence
  1023.     method? IF drop 305 THEN        ¥ methods have different security marker
  1024.     str-addr count evaluate            ¥ compile out-of-line code
  1025.                                     ¥ note - this will be wound up properly when
  1026.                                     ¥  we hit the ; or ;m
  1027. ;
  1028. PPC? [IF] ppc_immediate [ELSE] immediate [THEN]
  1029.  
  1030.  
  1031.  
  1032. ¥    ================  MOVE and ALIGNED_MOVE  =================
  1033. (*
  1034. I'm still deciding what's the best way to handle these.  I think that
  1035. for an aligned move of more than a couple of cells, it's OK to compile
  1036. a branch-on-count loop, since branch prefetch will get rid of any branch
  1037. latency, and there'll be no pipeline stall since the branch will only
  1038. depend on the count register.
  1039.  
  1040. For move_h, the moves could overlap, so for now I'll just do a call to
  1041. the compiled definition for MOVE, which will just call BlockMoveData.  Later
  1042. I could check the operands and use alignedMove if I can detect at compile
  1043. time that the move is aligned and non-overlapped.
  1044.  
  1045. *)
  1046.  
  1047. : Move_h        call_h  ;
  1048.  
  1049. (*    For alignedMove, we can assume the starting addresses are aligned, and
  1050.     there's no overlap.  If the move is short enough, I'll just compile
  1051.     some inline load and store instructions.  Otherwise I'll call the
  1052.     compiled defn for ALIGNED_MOVE, which will use a loop or a call to
  1053.     BlockMoveData.
  1054. *)
  1055.  
  1056. : AlignedMove_h  { ¥ len cnt offs remainder -- }
  1057.     1 operands
  1058.     refType: opnd1  litRef =
  1059.     IF    lit: opnd1  -> len
  1060.         len 20 <=
  1061.         IF    drop        ¥ we'll generate inline instructions.  We 
  1062.                         ¥  don't need the cfa of aligned_move
  1063.             len 2 >> -> cnt
  1064.             len 3 and -> remainder
  1065.             0 -> offs
  1066.             cnt FOR
  1067.                 postpone over  offs postpone literal  postpone +
  1068.                 postpone @
  1069.                 postpone over  offs postpone literal  postpone +
  1070.                 postpone !
  1071.                 4 ++> offs
  1072.             NEXT
  1073.             remainder FOR
  1074.                 postpone over  offs postpone literal  postpone +
  1075.                 postpone c@
  1076.                 postpone over  offs postpone literal  postpone +
  1077.                 postpone c!
  1078.                 1 ++> offs
  1079.             NEXT
  1080.             postpone 2drop   EXIT
  1081.         THEN
  1082.     THEN
  1083.     opnd1 push  call_h
  1084. ;
  1085.  
  1086.  
  1087.  
  1088. ¥    ================== MODULE SUPPORT ====================
  1089.  
  1090. PPC?
  1091. [IF]
  1092.  
  1093. (*
  1094. Here's the format of an imported word:
  1095.     n bytes        header
  1096.     2 bytes        handler code $BD2E
  1097.     2 bytes        export table offset for this word
  1098.     4 bytes        reloc addr of module object
  1099.  
  1100. We come here to imported_h when a call to an imported word has
  1101. to be compiled.  We compile a push of the xt of the word, then a
  1102. call to enterMod, which does the main work.  We put enterMod in
  1103. zModules, since it has to do a late-bound call to the module
  1104. object, and this is much easier if it's not in the target
  1105. compilation, and is also quicker to debug.
  1106. *)
  1107.  
  1108. : IMPORTED_H  ( xt -- )
  1109.     lit_addr                    ¥ compile push of xt, for enterMod
  1110.     ['] enterMod  call_h        ¥ then compile call to enterMod
  1111.                                 ¥  which does the call to the module
  1112. ;
  1113.  
  1114. [THEN]
  1115.  
  1116.  
  1117. ¥    ================== UTILITY PPC ROUTINES ====================
  1118.  
  1119. PPC? not
  1120. [IF]
  1121.  
  1122. : (REG)    ¥ ( reg# code -- )  defining word defining a register.
  1123.     ppc_header
  1124.     $ BD0A codeW,        ¥ handler code for reg_h
  1125.     $ FF02  codeW,        ¥ extra info mark, 2 bytes extra info
  1126.     ( code ) codeC,
  1127.     ( reg# ) codeC,
  1128.     0 codeW,            ¥ align
  1129. ;
  1130.  
  1131. : GPR  ( reg# -- )  3 (reg)  ;    ¥ 3 = gpr -- we used it for D reg on 68k
  1132. : FPR  ( reg# -- )    4 (reg)  ;    ¥ 4 = fpr
  1133.  
  1134. [THEN]
  1135.  
  1136. mainData_reg    gpr  MAINDATA
  1137. modData_reg        gpr  MODDATA
  1138. mainCode_reg    gpr  MAINCODE
  1139. modCode_reg        gpr  MODCODE
  1140. SP_reg            gpr  SP
  1141. RP_reg            gpr  RP
  1142. FSP_reg            gpr  FSP
  1143. obj_base_reg    gpr  (^BASE)
  1144. ¥ I_reg            gpr  I    - moved to pnuc1 since we still need orig defn
  1145. do_limit_reg    gpr  do_limit
  1146. RTOC_reg        gpr  RTOC
  1147. 1                gpr  sys_SP
  1148. 0                gpr  GPR0
  1149. rX_reg            gpr  rX
  1150. rY_reg            gpr  rY
  1151. 31                gpr  LOCREG            ¥ for temp objects - gets patched to
  1152.                                     ¥  the appropriate reg# by temp{
  1153.  
  1154. 31                gpr  ^constData        ¥ points to constant data for curr
  1155.                                     ¥  defn - patched to approp reg#
  1156.                                     ¥  by set_constData_reg
  1157.                                 
  1158.                                 
  1159.                         
  1160.  
  1161. 14                fpr  0.0        ¥ we always have zero in fpr14
  1162.  
  1163.  
  1164. ¥ IMPORTANT NOTE:  Since we sometimes save and restore FPRs onto the
  1165. ¥  return stack, we always keep RP 8-byte aligned.  So >R and R< 
  1166. ¥  use an 8 byte increment/decrement, not 4.  We provide >Rx and
  1167. ¥  R>x for internal use only, which don't 8-byte align, for setting
  1168. ¥  up things like DO loops where we can be sure we'll end up 8-byte
  1169. ¥  aligned anyway.
  1170.  
  1171. : (>R)  { 8align? -- }
  1172.     1 operands
  1173.     opnd1 RP_reg 
  1174.     8align? if -8 else 1cell negate then  true  push_to_mem
  1175.     ( false -> leaf? )
  1176. ;
  1177.  
  1178. (*    The idea of the "false -> leaf?" was, that if we're in a leaf
  1179.     proc, the return addr isn't on the return stack, and this might
  1180.     break some code that tries to access the rtn addr with rtn stack
  1181.     operations.  But this sort of monkeying with the rtn addr is highly
  1182.     nonstandard, and would never work anyway if there are locals, so
  1183.     we're not going to support it.
  1184. *)
  1185.  
  1186.     
  1187. : (R>)    { 8align? -- }
  1188.     getFreeReg: GPRs  >gpr: res1
  1189.     RP_reg 0
  1190.     8align? if 8 else 1cell then  compPull: GPRs
  1191.     res1 push
  1192.     ( false -> leaf? )  ;
  1193.  
  1194. ¥ >R, R> and R@ are in cg-cond.
  1195.  
  1196. forward marker_h
  1197.  
  1198. : NIMPL
  1199.     ." selector not implemented: "
  1200.     hex svSelector .  ."   opcode: " svOpcode . cr
  1201.     decimal
  1202.     1 die
  1203. ;
  1204.  
  1205. ppc?
  1206. [IF]
  1207.  
  1208. : does_h  { xt -- }
  1209.     xt 2+ @abs        ¥ addr of data area of CREATEd word
  1210.     lit_addr        ¥ compile a push of that addr for the runtime
  1211.                     ¥  (does) code
  1212.     xt 6 + @abs        ¥ xt of the runtime code
  1213.     call_h
  1214. ;
  1215.  
  1216. [ELSE]
  1217.  
  1218. : does_h    nimpl  ;
  1219.  
  1220. [THEN]
  1221.  
  1222.  
  1223. : compPlLoop    nimpl  ;
  1224. : hDoEx            nimpl  ;
  1225. : hcompimp        nimpl  ;
  1226. : bit_h            nimpl  ;
  1227. : hLoadBA        nimpl  ;
  1228. : FixDoes        nimpl  ;
  1229. : hPatch        nimpl  ;
  1230. ¥ : Floc_h        nimpl  ;
  1231. ¥ : Fcon_h        nimpl  ;
  1232. ¥ : Fval_h        nimpl  ;
  1233. : FP1_h            nimpl  ;
  1234. : FP2_h            nimpl  ;
  1235. : hcompFPUL        nimpl  ;
  1236. : FCRcon_h        nimpl  ;
  1237. : hColA            nimpl  ;
  1238. : hDefnEnd        nimpl  ;
  1239. : colNoOpt_h    nimpl  ;
  1240. : hComputedJMP    nimpl  ;
  1241. : hEB            nimpl  ;
  1242.  
  1243. ppc? not [if]
  1244. : imported_h        nimpl  ;
  1245. : class_in_mod_h    nimpl  ;
  1246. [then]
  1247.  
  1248.  
  1249. (*
  1250. PPC_compile is the main word which gets called from the Mops system to
  1251. compile PPC code.  We do this by setting PPC? true, and setting the
  1252. vector PPCvec to point to PPC_compile.
  1253. This calls PPC_interpret if STATE is zero.
  1254. On the PPC we need it to be a forward defn, hence what follows...
  1255. *)
  1256.  
  1257. PPC? not
  1258. [IF]
  1259.   forward  PPC_compile
  1260. [THEN]
  1261.  
  1262.  
  1263. ¥ ppc? [if] +echox [then]
  1264.  
  1265. : PPC_interpret  ( maybe xt here ) { handler opcode ¥ hndlr_code -- }
  1266.  
  1267.     handler    $ FF00 and  -> hndlr_code
  1268.  
  1269. [ ppc? not ]
  1270. [if]
  1271.     hndlr_code $ BE00 =
  1272.     IF  ." can't execute a PPC colon defn on 68k!" 1 die  THEN
  1273. [then]
  1274.  
  1275. ¥    hndlr_code $ BC00 <>
  1276. ¥    IF  ." can't execute this PPC word on 68k!"  1 die  THEN
  1277.     
  1278.     handler  $ FF and
  1279. [ PPC? [IF] hexx [ELSE] hex [THEN] ]
  1280.     SELECT[    1    ]=>        ¥ maybe it's OK to execute a 68k word?  Let's see...
  1281.                     $ deadbeef $ 103 2drop  execute
  1282.  
  1283.           [    2    ]=>        2+ @                ¥ const_h
  1284.           [    3    ]=>        2+ @abs @            ¥ val_h
  1285.           [    4    ]=>        2+ @abs                ¥ create_h
  1286.  
  1287.           [    8    ]=>        $ deadbeef $ 104 db ppc? drop 2drop  !        ¥ store_h 
  1288.           [    B    ]=>        2+ @abs                ¥ obj_h
  1289.           [    1D    ]=>        ppc_obj                ¥ class name - i.e. create
  1290.                                               ¥  an object of that class
  1291.           [    38    ]=>                            ¥ hNoOpt is a no-op on PPC
  1292.           [    3C    ]=>        inline_h            ¥ inlines are sometimes
  1293.                                               ¥  OK in interpret mode
  1294.           [    41    ]=>        marker_h
  1295.  
  1296.          DEFAULT=>        ." illegal selector for PPC_interpret: " .h cr
  1297.     ]SELECT
  1298. [ PPC? [IF] decimalx [ELSE] decimal [THEN] ]
  1299. ;
  1300.  
  1301.  
  1302. :f PPC_compile  ( maybe xt here ) { handler opcode ¥ hndlr_code -- }
  1303.  
  1304.     PPC? NIF ." whooops" 1 die  THEN
  1305.  
  1306.     0 -> operation  0 -> subOperation
  1307.     opcode -> svOpcode  0 -> svSelector
  1308.  
  1309.     handler    $ FF00 and  -> hndlr_code
  1310.  
  1311.     hndlr_code $ FF00 =
  1312.     IF        ¥ it's a 68k-style handler code - convert to PPC equivalent
  1313.         handler negate 2/  -> handler
  1314.     THEN
  1315.  
  1316. [ ppc? not ]
  1317. [IF]
  1318.     state NIF  handler opcode  PPC_interpret  EXIT  THEN
  1319. [THEN]
  1320.  
  1321.     hndlr_code $ BE00 =
  1322.     IF  call_h  EXIT  THEN          ¥ normal PPC call
  1323.  
  1324.     handler    $ FFFF and  $ BF01 =
  1325.     IF  call_extern  EXIT  THEN      ¥ external call (SYSCALL or EXTERN)
  1326.  
  1327.     handler  $ FF and  -> svSelector
  1328.  
  1329.     [ debug? ] [if]
  1330.         ." selector " svSelector .h  ."  opcode " svOpcode .h  cr
  1331.     [then]
  1332.     
  1333. [ PPC? [IF] hexx [ELSE] hex [THEN] ]
  1334.     svSelector
  1335.     SELECT[    1    ]=>        cr ." can't compile a call to a 68k word from PPC code!"
  1336.                         1 die
  1337.  
  1338.           [    2    ]=>        const_h
  1339.           [    3    ]=>        val_h
  1340.           [    4    ]=>        create_h
  1341.           [    5    ]=>        vect_h
  1342.           [    6    ]=>        pm_h
  1343.           [    7    ]=>        @_h
  1344.           [    8    ]=>        !_h
  1345.           [    9    ]=>        callStr_h
  1346.           [    A    ]=>        reg_h
  1347.           [    B    ]=>        obj_h
  1348.           [    C    ]=>        does_h
  1349.           [    D    ]=>        loc_h
  1350.           [    E    ]=>        litAddr_h
  1351.           [    F    ]=>        pushDesc_h
  1352.           [    10    ]=>        cmp_h
  1353.           [    11    ]=>        postpone literal    ¥ "hLiteral" on 68k is same as literal
  1354.           [    12    ]=>        CompExit
  1355.           [    13    ]=>        CompJSRlong
  1356.           [    14    ]=>        pif
  1357.           [    15    ]=>        compPlLoop
  1358.           [    16    ]=>            ¥ hmentry does nothing - we handle at compile_prolog
  1359.           [    17    ]=>        [ ppc? ] [if] dbgr [else] PLentry [then]
  1360.                               ¥ this handler code isn't used in PPC code - PLentry is
  1361.                               ¥  called directly from { etc.
  1362.           [    18    ]=>        heb
  1363.           [    19    ]=>        ¥ hStkObj    - never called from here?
  1364.                               to_be_written
  1365.           [    1A    ]=>        hDoEx
  1366.           [    1B    ]=>        genaddr
  1367.           [    1C    ]=>        genxaddr
  1368.           [    1D    ]=>        class_h        ¥ note - won't get called on 68k - ppc_obj
  1369.                                       ¥  is what gets called
  1370.           [    1E    ]=>        hcompimp
  1371.           [    1F    ]=>        val_h        ¥ objPtr_h - fetches are identical to values
  1372.           [    20    ]=>        bit_h
  1373.           [    21    ]=>        swap_h
  1374.           [    22    ]=>        hLoadBA
  1375.           [    23    ]=>        FixDoes
  1376.           [    24    ]=>        hPatch
  1377.           [    25    ]=>        Floc_h
  1378.           [    26    ]=>        Fcon_h
  1379.           [    27    ]=>        Fval_h
  1380. ¥          [    28    ]=>        FP1_h
  1381. ¥          [    29    ]=>        FP2_h
  1382.           [    2A    ]=>        FPcmp_h
  1383.           [    2B    ]=>        hcompFPUL
  1384.           [    2C    ]=>        FCRcon_h
  1385.           [    2D    ]=>        class_h        ¥ actually class_in_mod_h, but they're
  1386.                                       ¥  exactly the same!
  1387.           [    2E    ]=>        imported_h
  1388.           [    2F    ]=>        hColA
  1389.           [    30    ]=>        shift_h
  1390.           [    31    ]=>        hDefnEnd
  1391.           [    32    ]=>        F@_h
  1392.           [    33    ]=>        F!_h
  1393.           [    34    ]=>        builds_h
  1394.           [    35    ]=>        MultDiv_h
  1395.           [    36    ]=>        Move_h
  1396.           [    37    ]=>        AlignedMove_h
  1397.           [    38    ]=>            ¥ hNoOpt is a no-op on the PPC
  1398.           [    39    ]=>        colNoOpt_h
  1399.           [    3A    ]=>        hComputedJMP
  1400.           [    3B    ]=>        dynVect_h
  1401.           [    3C    ]=>        inline_h            ¥ won't be used for  as on 68k
  1402.           [    3D    ]=>        sVect_h                ¥ won't be used for RBsysCall ditto
  1403.  
  1404. ¥ these following ones aren't defined or used on the 68k:
  1405.  
  1406. ¥          [    3E    ]=>        >r_h
  1407. ¥          [    3F    ]=>        r>_h
  1408.           [    40    ]=>        inline_h            ¥ inline methods
  1409.           [    41    ]=>        marker_h
  1410.           [    42    ]=>        SF@_h
  1411.           [    43    ]=>        SF!_h
  1412.           
  1413.          DEFAULT=>        ." illegal selector: $" .h  cr 1 die
  1414.          [ ppc? ] [if] dbgr [then]
  1415.     ]SELECT
  1416. [ PPC? [IF] decimalx [ELSE] decimal [THEN] ]
  1417. ;f
  1418.  
  1419.  
  1420. (*                ============================
  1421.  
  1422.     ?trap is just for the code generator.  It converts a preceding comparison
  1423.     to a trap instruction, for 1-instruction bounds checking.  We trap if
  1424.     the comparison result was true.
  1425.  
  1426.                   ============================
  1427. *)
  1428.  
  1429. : ?TRAP  { ¥ TO_bit# unsigned? -- }
  1430.     1 operands
  1431.     [ debug? ] [if]
  1432.         ." ?trap - opnd1:" cr  print: opnd1
  1433.     [then]
  1434.     refType: opnd1
  1435.     litRef =
  1436.     IF                ¥ operands to comparison were known at compile time, so
  1437.                     ¥  we can do the check straight away:
  1438.         lit: opnd1  0EXIT
  1439.         ." range check error found at compile time"  1 die
  1440.     THEN
  1441.  
  1442.     CR: opnd1  select: CRs
  1443.  
  1444. ¥ we work out the TO-field bits to set, based on the condition in
  1445. ¥  opnd1 and whether the comparison was signed or unsigned.  The 3
  1446. ¥  leftmost bits are the same as CR field bits, but then there are
  1447. ¥  2 more bits for u< and u>.
  1448.  
  1449.     get: ivar> bit# in opnd1  -> TO_bit#
  1450.     get: ivar> opType in CRs  otUCMP =  -> unsigned?
  1451.     unsigned?  IF  3 ++> TO_bit#  THEN
  1452.     $ 10 TO_bit# >>
  1453.     unsigned?
  1454.     IF        get: ivar> 1_is_true? in opnd1  NIF  $ 07    xor  THEN
  1455.     ELSE    get: ivar> 1_is_true? in opnd1    NIF  $ 1C    xor  THEN
  1456.     THEN
  1457.     put: ivar> subType in CRs
  1458.     otTrap put: ivar> opType in CRs
  1459.     recompile: CRs
  1460.     clear: CRs            ¥ not a CR op any more
  1461. ;
  1462. PPC? [IF]  ppc_immediate  [ELSE]  immediate  [THEN]
  1463.  
  1464. (*                ============================
  1465.  
  1466.    Here we define some ops as immediate macros using eval" - these were primitives
  1467.    in the 68k version, but our PPC code generator will produce optimum code from
  1468.    the macros - much better than calling out-of-line code.
  1469.  
  1470.                   ============================
  1471. *)
  1472.  
  1473. PPC? 
  1474. [IF]
  1475.  
  1476. : ?DUP    inline{ dup if dup then}  ;
  1477. : 0DUP    inline{ dup nif dup then} ;
  1478.  
  1479. [ELSE]
  1480.  
  1481. : ?DUP    eval" dup if dup then"  ;    immediate
  1482. : 0DUP    eval" dup nif dup then"  ;    immediate
  1483.  
  1484. [THEN]
  1485.  
  1486. (*                    ============================
  1487.  
  1488.    Here we define any defining words we need to build special kinds of
  1489.    headers on the PPC.
  1490.    
  1491.    Generally these headers contain a handler code and extra info bytes which just
  1492.    give instructions to the code generator, and whose meaning is implied by the
  1493.    particular handler code.  These bytes are headed by ah "extra info mark" - since
  1494.    this comes in the same position as the flag bytes on a normal colon defn, we'll
  1495.    use a value which is impossible for the flag bytes, just to prevent confusion.
  1496.    We'll use FFxx, where xx is the number of extra info bytes (excluding the mark).
  1497.    
  1498.    Then if normal out-of-line code follows (which can be called by EXECUTE), it
  1499.    will follow the extra info bytes.  We'll pad to an odd-halfword boundary, then
  1500.    put the normal flag bytes, then the code.
  1501.  
  1502.                       ============================
  1503. *)
  1504.  
  1505. ¥ Use special_op thus:
  1506.  
  1507. ¥ $ BD06 otAdd  special_op +  ;
  1508.  
  1509. ¥ The handler code and the extra info code is pushed before special_op, then
  1510. ¥ the name follows.
  1511.  
  1512.  
  1513. : special_op  { hndlr code ¥ cfa --  }
  1514.     ppc_header
  1515.     hndlr codeW,        ¥ pm_h code
  1516.     CDP -> cfa
  1517.     $ FF02 codeW,        ¥ extra info mark, 2 bytes extra info
  1518.     code codeW,            ¥ the info
  1519.     0 codeW,            ¥ initial flag bytes for out-of-line code
  1520.                         ¥  (we should now be aligned)
  1521.     false -> method?
  1522.     false ppc_entry        ¥ compile entry for OUL code
  1523.     cfa hndlr code  ppc_compile            ¥ compile  OUL code
  1524.     
  1525.     [ ppc? ] [if]
  1526.         curr-def 2- (;)  300 ?defn        ¥ wind up OUL code - this is
  1527.                                         ¥  the same as "postpone ;" but
  1528.                                         ¥  we can't do that here!
  1529.     [else]
  1530.         postpone ;
  1531.     [then]
  1532. ;
  1533.  
  1534.  
  1535. PPC? not
  1536. [IF]
  1537.  
  1538. : dummy_op  { hndlr -- }    ¥ currently this is just used to define locParm and
  1539.                             ¥  FlocParm, which don't do anything in themselves
  1540.                             ¥  except have handler codes which cause locals to be
  1541.                             ¥  accessed.
  1542.     ppc_header
  1543.     hndlr codeW,
  1544.     0 codeW,        ¥ align
  1545. ;
  1546.  
  1547. [THEN]
  1548.  
  1549.  
  1550. : fetch_op  { code flags ¥ cfa -- }
  1551.     ppc_header
  1552.     $ BD07 codeW,        ¥ @_h code
  1553.     CDP -> cfa
  1554.     $ FF04 codeW,        ¥ extra info mark, 4 bytes extra info
  1555.     code codeW,  flags codeW,
  1556.     0 codeW,            ¥ padding to get to odd halfword
  1557.     0 codeW,            ¥ initial flag bytes for out-of-line code
  1558.                         ¥  (we should now be aligned)
  1559.     false ppc_entry
  1560.     cfa  $ BD07  code  ppc_compile
  1561.  
  1562.     [ ppc? ] [if]
  1563.         curr-def 2- (;)  300 ?defn        ¥ wind up OUL code
  1564.     [else]
  1565.         postpone ;
  1566.     [then]
  1567. ;
  1568.  
  1569.  
  1570. : simple_op  { hndlr ¥ cfa -- }
  1571.     ppc_header
  1572.     hndlr codeW,        ¥ handler code
  1573.     CDP -> cfa
  1574.     0 codeW,            ¥ initial flag bytes for out-of-line code
  1575.                         ¥  (we should now be aligned)
  1576.     false -> method?
  1577.     false ppc_entry        ¥ compile entry for OUL code
  1578.     cfa hndlr 0  ppc_compile            ¥ compile  OUL code
  1579.  
  1580.     [ ppc? ] [if]
  1581.         curr-def 2- (;)  300 ?defn        ¥ wind up OUL code
  1582.     [else]
  1583.         postpone ;
  1584.     [then]
  1585. ;
  1586.  
  1587.  
  1588. PPC?
  1589. [IF]
  1590.   endload
  1591. [THEN]
  1592.  
  1593.  
  1594. 0    value    cg_CDP
  1595. 0    value    cg_DP
  1596. 0    value    norm_CDP
  1597. 0    value    norm_DP
  1598.  
  1599. : CG_CODE_START
  1600.     CDP -> norm_CDP    cg_CDP -> CDP
  1601.     cr
  1602.     ." code gen code start: $" CDP .h cr
  1603. ;
  1604.  
  1605. : CG_CODE_END
  1606.     cr cr
  1607.     ." code gen code end:  $"  CDP .h cr
  1608.     ." code gen code size: $"  CDP  cg_CDP - .h cr
  1609.     CDP nuc_code_start  u> IF ." cg code overran its area!" QUIT  THEN
  1610.     norm_CDP -> CDP
  1611. ;
  1612.  
  1613.  
  1614. : CG_DATA_START
  1615.     DP  -> norm_DP    cg_DP  -> DP
  1616.     ." code gen data start: $"  DP .h cr
  1617. ;
  1618.  
  1619. : CG_DATA_END
  1620.     cr cr
  1621.     ." code gen data end:  $"   DP .h cr
  1622.     ." code gen data size: $"    DP  cg_DP  - .h cr
  1623.     DP  nuc_data_start  u> IF ." cg data overran its area!" QUIT  THEN
  1624.     norm_DP -> DP
  1625. ;
  1626.  
  1627.  
  1628.  
  1629. : CROSS        ¥ crosses the fence into PPC-land - starts PPC compilation.
  1630.  
  1631. cr cr ." *************** PPC compilation started ***************" cr
  1632.  
  1633.     ['] PPC_compile  -> PPCvec
  1634.     true -> PPC?                    ¥ PPC compilation on
  1635.     true -> crossed?
  1636.  
  1637. ¥ Note: words such as CODE, which use a separate CDP, won't
  1638. ¥  work as expected until PPC? is set true, since before then
  1639. ¥  we keep it tied to DP so common code can be used.
  1640.  
  1641.     0 -> #P  0 -> #PL
  1642.     align4                    ¥ 4-byte align in data area
  1643.     DP -> data_start
  1644.     $ A000  reserve            ¥ put code up the dictionary, clear data area
  1645.  
  1646. ¥ now we set up the initial CDP, DP, code_start, code_limit, data_start
  1647. ¥  and data_limit
  1648.  
  1649.     DP
  1650.     dup  -> CDP  dup -> data_limit  dup -> code_start
  1651.     room +  -> code_limit
  1652.  
  1653.     $ 48000000 code,            ¥ put a branch at the start of the code, which
  1654.                                 ¥  will be resolved by INITIAL_ENTRY_POINT
  1655.                                 ¥  to our real initial entry point.
  1656.  
  1657.     info_block_size code_reserve    ¥ and then reserve space for the info block
  1658.                                     ¥  which follows.  This gets set up when we
  1659.                                     ¥  write the PEF
  1660.  
  1661.     0 -> 1st_defn                ¥ no defn yet
  1662.     data_start -> DP
  1663.  
  1664.     TOC_size  allot                ¥ initially allot TOC entries at start of data
  1665.  
  1666. ¥ now for the target compilation, we want the code generator to come
  1667. ¥  below the nucleus so we can omit it in installed apps.  So we now
  1668. ¥  allocate space for it in the code and data areas:
  1669.  
  1670.     CDP -> cg_CDP                ¥ the start of the cg's code area
  1671.     DP -> cg_DP
  1672.     $ 22000 code_reserve        ¥ currently we need about 203xx
  1673.     $ 8000 reserve                ¥ currently we need about 5Cxx
  1674.     
  1675. ¥ now we're where we want the nuc to start
  1676.     CDP -> nuc_code_start
  1677.     DP  -> nuc_data_start
  1678. ¥ data_start -> nuc_data_start  4 ++> nuc_data_start
  1679.  
  1680.  
  1681. ." code_start     "    code_start        .h cr
  1682. ." data_start     "    data_start        .h cr
  1683. ." nuc_code_start "    nuc_code_start    .h cr
  1684. ." nuc_data_start "    nuc_data_start    .h cr
  1685. ." mainCode       "    mainCode_val    .h cr
  1686. ." mainData       "    mainData_val    .h cr cr
  1687.  
  1688.     CDP $ D000 erase        ¥ clear code area which makes it easier to see what we generated
  1689.  
  1690.     gpr_call_cnt setup_cstk
  1691.     fpr_call_cnt setup_fcstk
  1692.     new: eq_ranges  new: const_data  new: sv_const_data
  1693. ;
  1694.  
  1695.  
  1696. : .STK        printall: cstk  ;
  1697. : .STK2        printall: cstk2  ;
  1698.  
  1699. : ENDPPC
  1700.     0 -> PPCvec
  1701.     true -> 68k?
  1702.     PPC? 0EXIT                    ¥ out if windup already done
  1703.     false -> PPC?
  1704.     CDP    -> code_limit
  1705.     DP    -> data_limit
  1706.     CDP -> DP                    ¥ put DP back to normal place
  1707. ;
  1708.  
  1709.  
  1710. : INITIAL_ENTRY_POINT
  1711.     CDP -> init_entry  ;        immediate
  1712.  
  1713. : .SIZE        ." code size: "  CDP 1st_defn -  . cr
  1714.             ." data size: "  DP data_start - . cr  ;
  1715.  
  1716.  
  1717. :f DASM        1st_defn CDP 2dup  set_disasm_call_range
  1718.             disasm_rng  cr
  1719. ;f
  1720.  
  1721. :f DCURR        curr-def-code CDP  set_disasm_call_range
  1722.             CDP dup 96 -  swap  disasm_rng  cr
  1723. ;f
  1724.  
  1725.  
  1726. : ZZ
  1727.     endPPC
  1728.     release: const_data
  1729.     gpr_call_cnt setup_cstk  ;
  1730.  
  1731. :f Z
  1732. ¥    endPPC
  1733.     .stk  dasm cr .size  ;f
  1734.  
  1735. : ZB  { #back -- }
  1736. ¥        endPPC
  1737.         .stk
  1738.         code_start CDP  set_disasm_call_range
  1739.         CDP dup  #back - swap  disasm_rng
  1740.         cr .size  ;
  1741.  
  1742. :f ZS    $ 200  zb  ;f
  1743. : ZL    $ 800  zb  ;
  1744.  
  1745. : DW    disasm_word  ;
  1746.  
  1747. : DF    ¥ "disassemble from"
  1748.     endPPC  .stk
  1749.     '  >link  CDP  dup set_disasm_call_range  disasm_rng
  1750.     cr  .size  ;
  1751.     
  1752.  
  1753. : RL    zz  rl  ;
  1754. : FM    zz  fm  ;
  1755.  
  1756. : WP    endPPC  write_pef  ;
  1757.  
  1758.  
  1759. :ppc_code (DBGR)
  1760.     r12    8 r2    lwz,
  1761.     r12    0 r12    lwz,
  1762.     r12            mtctr,
  1763.     r11    r3        mr,
  1764.     r12            mflr,
  1765.     r12    -4 r17    stwu,
  1766.                 bctrl,
  1767.     r12    r17        lwz,
  1768.     r17    r17 4    addi,
  1769.     r12            mtlr,
  1770.     r3    r11        mr,
  1771. ;ppc_code
  1772.  
  1773.  
  1774. : fix_sys_SP        ¥ Straight after the initial entry, we have to set up
  1775.                     ¥  a legal frame on the system stack.
  1776.     $ 7C320B78  code,                    ¥    mr        SP, sys_SP
  1777.     $ 7C0802A6  code,                    ¥    mflr    r0
  1778.     $ 90010008  code,                    ¥    stw        r0,8(sys_SP)
  1779.     sys_SP_framesize negate $ FFFF and
  1780.     $ 94210000  or code,                ¥    stwu    sys_SP, $-framesize(sys_SP)
  1781.     $ 90410014    code,                    ¥    stw        RTOC,20(sys_SP)
  1782.     0 >size: fcstk                        ¥ initially the FP stack isn't set up - this
  1783.                                         ¥  prevents any stores to it in the initial
  1784.                                         ¥  setup code
  1785. ;        immediate
  1786.  
  1787.  
  1788. : dbgr                        ¥ calls the debugger gracefully
  1789.     ['] (dbgr) cfa_adjust 2+  CDP  44  aligned_move
  1790.     44 ++> CDP
  1791.     CDP -> backstop_CDP        ¥ it's confusing if loads get hoisted here
  1792.     true -> ctr_clobbered?    ¥ since it is!
  1793. ;            immediate
  1794.  
  1795. : dbgrx                    ¥ calls the debugger ungracefully - but all regs
  1796.                         ¥  are intact!
  1797.     0 code,
  1798. ;        immediate
  1799.  
  1800.  
  1801. ¥ Some redefinitions, so we can still execute the 68k versions after CROSS:
  1802. : +echox    +echo  ;
  1803. : .errx        .err   ;
  1804. : wordsx    words  ;
  1805. : byex        bye  ;
  1806. : hexx        hex  ;
  1807. : decimalx    decimal  ;
  1808. : cx,        c,  ;
  1809. : allotx    allot  ;
  1810. : reservex    reserve  ;
  1811. : reloc!x    reloc!  ;
  1812. : dumpx        dump  ;
  1813. : endloadx    endload  ;
  1814. : //x        //  ;
  1815. : >namex    3-  -1 traverse  ;
  1816. : displ!x    displ!  ;
  1817. : relocCode,x    relocCode,  ;
  1818. : CDPx        CDP  ;
  1819. : DPx        DP   ;
  1820. : .gsx        .gs  ;
  1821. : zsx        zs  ;
  1822.  
  1823.  
  1824.  
  1825.  
  1826. ¥ These are useful for bug-hunting without having to load the whole PPC image:
  1827.  
  1828. : ROT    rot_cstk  ;        immediate
  1829.  
  1830. : DOWN    3 operands
  1831.         opnd3 push  opnd1 push  opnd2 push  ;        immediate
  1832.  
  1833.  
  1834. string+ s
  1835. file    aFile
  1836.  
  1837. : DFILE            ¥ disassemble file
  1838.     clear: aFile  -1 stdGet: aFile  0EXIT
  1839.     new: s  open: aFile  OK?
  1840.     aFile readAll: s  close: aFile drop
  1841.     lock: s
  1842.     all: s  over +  2dup swap 200 + swap set_disasm_call_range
  1843.     disasm_rng  cr
  1844.     release: s
  1845.     0 0  set_disasm_call_range
  1846. ;
  1847.